package com.peg.rules;

import com.peg.dataobjects.Context;
import com.peg.events.DebugEvent;

/**
 * @author sad
 */
public abstract class Rule {

    private String ruleName;
    private Rule[] _rules;
    private int start = -1;
    private int length = -1;
    private static DebugEvent debugEvent;

    public int getStart() {
        return start;
    }

    public void setStart(int start) {
        this.start = start;
    }

    public int getLength() {
        return length;
    }

    public void setLength(int length) {
        this.length = length;
    }

    public Rule() {
    }

    public String getRuleName() {
        return ruleName;
    }

    public void setRuleName(String ruleName) {
        this.ruleName = ruleName;
    }

    public void endRule(boolean result, Context context) {
    }

    abstract public boolean execute(Context context);

    public Rule setRules(Rule... rules) {
        for (int i = 0; i < rules.length; i++) {
            rules[i] = processRule(rules[i]);
        }

        _rules = rules;
        return this;
    }

    public Rule setRule(Rule rule) {
        _rules = new Rule[]{processRule(rule)};
        return this;
    }

    private static Rule processRule(Rule rule) {
        /*if (rule instanceof String) {
         return new StringRule((String) rule, false);
         } else if (rule instanceof Character) {
         return new StringRule("" + (Character) rule, false);
         }*/

        return rule;
    }

    public Rule[] getRules() {
        return _rules;
    }

    public Rule getRule() {
        return _rules[0];
    }

    public int lineNumber(int deep) {
        return Thread.currentThread().getStackTrace()[deep].getLineNumber();
    }

    public String fileName(int deep) {
        return Thread.currentThread().getStackTrace()[deep].getFileName();
    }

    protected boolean executeRule(Rule rule, Context context) {
        if (rule == null) {
            return false;
        }

        if (debugEvent != null) {
            debug(rule, context);
        }

        if (rule instanceof Rule) {
            return ((Rule) rule).execute(context);
        }
        /*
         if (rule instanceof Boolean) {
         return (Boolean) rule;
         }

         if (rule instanceof Functor) {
         Functor<Context, Boolean> f = (Functor<Context, Boolean>) rule;
         return f.execute(context);
         }

         if (rule instanceof FunctorVoid) {
         FunctorVoid<Context> f = (FunctorVoid<Context>) rule;
         f.execute(context);
         return true;
         }*/

        throw new RuntimeException("Rule should return boolean value");
    }

    @Override
    public String toString() {
        return "Rule";
    }

    public static void setDebugEvent(DebugEvent debugEvent) {
        Rule.debugEvent = debugEvent;
    }

    protected void debug(Rule rule, Context context) {
        if (rule.getStart() != -1) {
            debugEvent.debugEvent(rule, context);
        }
    }
}
